package com.sky.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.dto.*;
import com.sky.entity.*;
import com.sky.exception.AddressBookBusinessException;
import com.sky.exception.BaseException;
import com.sky.exception.OrderBusinessException;
import com.sky.exception.ShoppingCartBusinessException;
import com.sky.mapper.*;
import com.sky.properties.AddressProperties;
import com.sky.result.PageResult;
import com.sky.service.OrderService;
import com.sky.utils.HttpClientUtil;
import com.sky.utils.WeChatPayUtil;
import com.sky.vo.OrderPaymentVO;
import com.sky.vo.OrderStatisticsVO;
import com.sky.vo.OrderSubmitVO;
import com.sky.vo.OrderVO;
import com.sky.websocket.WebSocketServer;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.sky.constant.MessageConstant.ADDRESS_BOOK_IS_NULL;
import static com.sky.entity.Orders.*;

@Slf4j
@Service

public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private ShopCartMapper shopCartMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private AddressBookMapper addressBookMapper;
    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private AddressProperties addressProperties;
    @Autowired
    private WebSocketServer webSocketServer;


    /**
     * 提交订单
     *
     * @param ordersSubmitDTO
     * @return
     */
    @Override
    @Transactional
    public OrderSubmitVO submit(OrdersSubmitDTO ordersSubmitDTO) {
        //进行参数校验
        if (ordersSubmitDTO.getAddressBookId() == null
                || ordersSubmitDTO.getAmount() == null
                || ordersSubmitDTO.getEstimatedDeliveryTime() == null
                || ordersSubmitDTO.getPackAmount() == null
                || ordersSubmitDTO.getPayMethod() == 0
        ) {
            log.error("提交订单参数校验失败");
            //抛出异常
            throw new BaseException("非法参数");
        }
        //判断收货地址是否存在
        AddressBook addressBook = addressBookMapper.getById(ordersSubmitDTO.getAddressBookId());
        if (BeanUtil.isEmpty(addressBook)) {
            log.error("收货地址不存在");
            throw new AddressBookBusinessException(ADDRESS_BOOK_IS_NULL);
        }
        //构建商家坐标参数
        String origin = buildCoordinates(null);
        log.info("商家坐标参数:{}", origin);
        //构建用户坐标参数
        String destination = buildCoordinates(addressBook);
        log.info("用户坐标参数:{}", destination);
        //判断是否超出配送距离
        judeDistance(origin, destination);
        //调用getOrders添加购物车
        Orders orders = getOrders(ordersSubmitDTO, addressBook);
        //构建vo数据
        return OrderSubmitVO.builder().id(orders.getId())
                .orderNumber(orders.getNumber())
                .orderAmount(orders.getAmount())
                .orderTime(orders.getOrderTime())
                .build();
    }

    private void judeDistance(String origin, String destination) {
        HashMap<String, String> map = new HashMap<>();
        map.put("ak", addressProperties.getAk());
        map.put("origin", origin);
        map.put("destination", destination);
        String resultJson = HttpClientUtil.doGet(addressProperties.getDrivingURL(), map);
        //解析响应结果
        JSONObject jsonObject = JSON.parseObject(resultJson);
        //获取距离
        String distance = jsonObject.getJSONObject("result").getJSONArray("routes").getJSONObject(0).getString("distance");
        log.info("距离:{}", distance);
        if (Integer.valueOf(distance) > 500000) {
            //配送距离超过5000米
            throw new OrderBusinessException("超出配送范围");
        }
    }

    /**
     * 构建坐标
     *
     * @param addressBook
     * @return
     */
    private String buildCoordinates(AddressBook addressBook) {
        //获取远程调用地址
        String geoCodeURL = addressProperties.getGeoCodeURL();
        //构建查询参数
        HashMap<String, String> map = new HashMap<>();
        //经度
        String lng = "";
        //纬度
        String lat = "";
        map.put("ak", addressProperties.getAk());
        map.put("output", "json");
        map.put("callback", "showLocation");
        if (addressBook != null) {
            //获取用户地址
            String userAddress = addressBook.getProvinceName() + addressBook.getDistrictName() + addressBook.getDetail();
            map.put("address", userAddress);
            HashMap<String, String> resultMap = getLatAndLng(geoCodeURL, map);
            lng = resultMap.get("lng");
            lat = resultMap.get("lat");
        } else {
            //获取商家地址
            String shopAddress = addressProperties.getAddress();
            map.put("address", shopAddress);
            HashMap<String, String> resultMap = getLatAndLng(geoCodeURL, map);
            lng = resultMap.get("lng");
            lat = resultMap.get("lat");
        }
        return lat + "," + lng;
    }

    /**
     * 获取经纬度
     *
     * @return
     */
    private HashMap<String, String> getLatAndLng(String url, HashMap<String, String> map) {
        // 创建一个HashMap用于存储查询结果
        HashMap<String, String> resultMap = new HashMap<>();
        // 调用HttpClientUtil类的doGet方法发起HTTP GET请求，并将结果存储在resultJson变量中
        String resultJson = HttpClientUtil.doGet(url, map);
        // 将resultJson按照JSON格式解析为jsonObject
        JSONObject jsonObject = JSON.parseObject(resultJson.substring(resultJson.indexOf("{"), resultJson.lastIndexOf("}") + 1));
        // 从jsonObject中提取lng和lat值
        String lng = jsonObject.getJSONObject("result").getJSONObject("location").getString("lng");
        String lat = jsonObject.getJSONObject("result").getJSONObject("location").getString("lat");
        // 对lng和lat进行处理，确保精度达到小数点后6位
        if (lng.split("\\.")[1].length() > 6) {
            lng = new BigDecimal(lng).setScale(6, BigDecimal.ROUND_HALF_UP).toString();
        }
        if (lat.split("\\.")[1].length() > 6) {
            lat = new BigDecimal(lat).setScale(6, BigDecimal.ROUND_HALF_UP).toString();
        }
        // 将处理后的lng和lat值存入resultMap
        resultMap.put("lng", lng);
        resultMap.put("lat", lat);
        // 返回resultMap
        return resultMap;
    }


    /**
     * 构建订单
     *
     * @param ordersSubmitDTO
     * @param addressBook
     * @return
     */
    private Orders getOrders(OrdersSubmitDTO ordersSubmitDTO, AddressBook addressBook) {
        //判断用户的购物车是否为空
        ShoppingCart shoppingCart = ShoppingCart.builder()
                .userId(BaseContext.getCurrentId()).build();
        List<ShoppingCart> shoppingCartList = shopCartMapper.getCurrentUserShopCart(shoppingCart);
        if (CollUtil.isEmpty(shoppingCartList)) {
            throw new ShoppingCartBusinessException(MessageConstant.SHOPPING_CART_IS_NULL);
        }
        //4.复制dto的对象为订单实体对象
        Orders orders = BeanUtil.copyProperties(ordersSubmitDTO, Orders.class);
        //设置订单号
        orders.setNumber(UUID.fastUUID().toString(true));
        //设置用户id
        orders.setUserId(BaseContext.getCurrentId());
        //设置收获信息
        orders.setConsignee(addressBook.getConsignee());
        orders.setPhone(addressBook.getPhone());
        orders.setAddress(addressBook.getDetail());
        //5.设置状态信息
        orders.setStatus(PENDING_PAYMENT);//待支付
        orders.setPayStatus(UN_PAID);//未支付
        //设置订单时间
        orders.setOrderTime(LocalDateTime.now());
        //6.新增订单数据(回填主键id)
        orderMapper.insert(orders);
        //7.复制购物车数据为订单数据，且设置订单id
        List<OrderDetail> orderDetailList = shoppingCartList.stream().map(e -> {
            OrderDetail orderDetail = BeanUtil.copyProperties(e, OrderDetail.class);
            orderDetail.setOrderId(orders.getId());
            return orderDetail;
        }).collect(Collectors.toList());
        //8.新增订单详情数据
        orderDetailMapper.insertBatch(orderDetailList);
        //9.清空购物车
        shopCartMapper.cleanCart(BaseContext.getCurrentId());
        return orders;
    }

    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

        //调用微信支付接口，生成预支付交易单
        JSONObject jsonObject = weChatPayUtil.pay(
                ordersPaymentDTO.getOrderNumber(), //商户订单号
                new BigDecimal(0.01), //支付金额，单位 元
                "苍穹外卖订单", //商品描述
                user.getOpenid() //微信用户的openid
        );

        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
            throw new OrderBusinessException("该订单已支付");
        }

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));

        return vo;
    }

    /**
     * 支付成功，修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 根据订单号查询订单
        Orders ordersDB = orderMapper.getByNumber(outTradeNo);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();
        Map map = new HashMap();
        map.put("type", 1);//消息类型，1表示来单提醒
        map.put("orderId", orders.getId());
        map.put("content", "订单号：" + outTradeNo);

        //通过WebSocket实现来单提醒，向客户端浏览器推送消息
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
        orderMapper.update(orders);
    }

    /**
     * 接受订单
     *
     * @param ordersConfirmDTO
     */
    @Override
    public void confirm(OrdersConfirmDTO ordersConfirmDTO) {
        Orders orders = Orders.builder()
                .id(ordersConfirmDTO.getId())
                .status(Orders.CONFIRMED)
                .build();
        orderMapper.update(orders);
    }

    /**
     * 拒绝订单
     *
     * @param ordersRejectionDTO
     */
    @Override
    public void rejection(OrdersRejectionDTO ordersRejectionDTO) {
        Orders orders = builder()
                .id(ordersRejectionDTO.getId())
                .status(Orders.CANCELLED)
                .cancelTime(LocalDateTime.now())
                .rejectionReason(ordersRejectionDTO.getRejectionReason()).build();
        orderMapper.update(orders);
    }

    /**
     * 派送
     *
     * @param id
     */
    @Override
    public void delivery(Long id) {
        //获取当前订单信息
        Orders currentOrder = orderMapper.orderInformation(id);
        Orders orders = new Orders();
        orders.setId(currentOrder.getId());
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
        orderMapper.update(orders);

    }

    /**
     * 完成订单
     *
     * @param id
     */
    @Override
    public void complete(Long id) {
        //获取当前订单信息
        Orders currentOrder = orderMapper.orderInformation(id);
        Orders orders = new Orders();
        orders.setId(currentOrder.getId());
        orders.setDeliveryTime(LocalDateTime.now());
        orders.setStatus(Orders.COMPLETED);
        orderMapper.update(orders);
    }

    /**
     * 历史订单
     *
     * @param page
     * @param pageSize
     * @param status
     * @return
     */
    @Override
    public PageResult historyOrders(int page, int pageSize, Integer status) {
        //开启分页
        PageHelper.startPage(page, pageSize);
        //进行分页查询
        OrdersPageQueryDTO ordersPageQueryDTO = new OrdersPageQueryDTO();
        ordersPageQueryDTO.setStatus(status);
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        Page<Orders> ordersPage = orderMapper.conditionSearch(ordersPageQueryDTO);
        //封装OrderVo数据
        List<OrderVO> orderVOS = BeanUtil.copyToList(ordersPage.getResult(), OrderVO.class);
        for (OrderVO orderVO : orderVOS) {
            orderVO.setOrderDetailList(orderDetailMapper.orderDetails(orderVO.getId()));
        }

        return new PageResult(ordersPage.getTotal(), orderVOS);
    }

    /**
     * 查询订单详情
     *
     * @param id
     * @return
     */
    @Override
    public OrderVO ordersDetail(Long id) {
        OrderVO orderVO = orderMapper.orderInformation(id);
        List<OrderDetail> list = orderDetailMapper.orderDetails(id);
        orderVO.setOrderDetailList(list);
        return orderVO;
    }

    /**
     * 用户取消订单
     *
     * @param id
     */
    @Override
    public void userCancel(Long id) {
        //获取当前订单信息
        Orders orders = orderMapper.orderInformation(id);
        //修改订单状态--取消
        orders.setStatus(CANCELLED);
        //设置取消原因
        orders.setCancelReason("用户取消订单");
        //设置订单取消时间
        orders.setCancelTime(LocalDateTime.now());
        //修改订单信息
        orderMapper.update(orders);
    }

    /**
     * 再来一单
     *
     * @param id
     */
    @Override
    public void repetition(Long id) {
        //获取当前订单信息
        List<OrderDetail> list = orderDetailMapper.orderDetails(id);
        //重新添加到购物车
        List<ShoppingCart> shoppingCartList = BeanUtil.copyToList(list, ShoppingCart.class);
        shoppingCartList.forEach(shoppingCart -> {
            shoppingCart.setUserId(BaseContext.getCurrentId());
            shoppingCart.setCreateTime(LocalDateTime.now());
        });
        //进行添加
        shopCartMapper.insertBatch(shoppingCartList);
    }

    /**
     * 用户催单
     *
     * @param id
     */
    @Override
    public void reminder(Long id) {
        // 查询订单是否存在
        Orders orders = orderMapper.getById(id);
        if (orders == null) {
            throw new OrderBusinessException(MessageConstant.ORDER_NOT_FOUND);
        }

        //基于WebSocket实现催单
        Map map = new HashMap();
        map.put("type", 2);//2代表用户催单
        map.put("orderId", id);
        map.put("content", "订单号：" + orders.getNumber());
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
    }

    /**
     * 分页查询订单
     *
     * @param ordersPageQueryDTO
     * @return
     */
    @Override
    public PageResult conditionSearch(OrdersPageQueryDTO ordersPageQueryDTO) {
        //对象拷贝
        ordersPageQueryDTO.setUserId(BaseContext.getCurrentId());
        //开启分页
        PageHelper.startPage(ordersPageQueryDTO.getPage(), ordersPageQueryDTO.getPageSize());
        //进行分页查询
        Page<Orders> ordersPage = orderMapper.conditionSearch(ordersPageQueryDTO);
        //封装OrderVo数据
        List<OrderVO> orderVOS = BeanUtil.copyToList(ordersPage.getResult(), OrderVO.class);
        orderVOS.forEach(orderVO -> {
            List<OrderDetail> list = orderDetailMapper.orderDetails(orderVO.getId());
            StringJoiner stringJoiner = new StringJoiner(";");
            for (OrderDetail orderDetail : list) {
                String orderDetailName = orderDetail.getName();
                Integer orderDetailNumber = orderDetail.getNumber();
                if (orderDetailName != null && orderDetailNumber != null) {
                    stringJoiner.add(orderDetailName + "*" + orderDetailNumber);
                }
            }
            orderVO.setOrderDishes(stringJoiner.toString());
            orderVO.setOrderDetailList(list);
        });
        log.info("转换为Vo之后的数据--{}", orderVOS);
        return new PageResult(ordersPage.getTotal(), orderVOS);
    }

    /**
     * 订单详情查询
     *
     * @param id
     * @return
     */
    @Override
    public OrderVO details(Long id) {
        OrderVO orderVO = orderMapper.orderInformation(id);
        List<OrderDetail> list = orderDetailMapper.orderDetails(orderVO.getId());
        orderVO.setOrderDetailList(list);
        return orderVO;
    }

    /**
     * 订单取消
     *
     * @param ordersCancelDTO
     */
    @Override
    public void cancel(OrdersCancelDTO ordersCancelDTO) {
        //校验参数
        if (ordersCancelDTO.getId() == null || StrUtil.isBlank(ordersCancelDTO.getCancelReason())) {
            throw new BaseException("参数异常");
        }
        //查询取消的订单
        Orders orders = orderMapper.orderInformation(ordersCancelDTO.getId());
        //修改订单状态--取消
        orders.setStatus(CANCELLED);
        //设置取消原因
        orders.setCancelReason(ordersCancelDTO.getCancelReason());
        //设置订单取消时间
        orders.setCancelTime(LocalDateTime.now());
        //修改订单信息
        orderMapper.update(orders);
    }

    /**
     * 订单统计
     *
     * @return
     */

    @Override
    public OrderStatisticsVO statistics() {
        //获取所有订单信息
        List<Orders> list = orderMapper.getAllOrderInformation();
        //分组统计
        Map<Integer, List<Orders>> statusMap = list.stream().collect(Collectors.groupingBy(Orders::getStatus));
        OrderStatisticsVO orderStatisticsVO = new OrderStatisticsVO();
        statusMap.forEach((k, v) -> {
            if (k.equals(DELIVERY_IN_PROGRESS)) {
                orderStatisticsVO.setDeliveryInProgress(v.size());
            } else if (k.equals(TO_BE_CONFIRMED)) {
                orderStatisticsVO.setToBeConfirmed(v.size());
            } else if (k.equals(CONFIRMED))
                orderStatisticsVO.setConfirmed(v.size());
        });
        return orderStatisticsVO;
    }
}
